/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.meta.service;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONException;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.base.Strings;
import com.je.common.base.entity.func.FuncQueryStrategy;
import com.je.common.base.func.funcPerm.roleSqlAuth.RoleSqlAuthScopeVo;
import com.je.common.base.func.funcPerm.roleSqlAuth.RoleSqlAuthVo;
import com.je.common.base.mapper.query.Condition;
import com.je.common.base.mapper.query.Order;
import com.je.common.base.mapper.query.Query;
import com.je.common.base.service.AbstractQueryBuilderService;
import com.je.common.base.service.MetaDataPermCheckService;
import com.je.common.base.service.MetaResourceService;
import com.je.common.base.service.QueryBuilderService;
import com.je.common.base.util.SecurityUserHolder;
import com.je.common.base.util.StringUtil;
import com.je.ibatis.extension.conditions.ConditionsWrapper;
import com.je.ibatis.extension.enums.Conditions;
import com.je.meta.rpc.func.MetaFuncPermService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 查询条件构建器
 *
 * @author wangmm@ketr.com.cn
 * @date 2019/12/28
 */
@Service
public class QueryBuilderServiceImpl extends AbstractQueryBuilderService implements QueryBuilderService {

    @Autowired
    private MetaResourceService metaResourceService;
    @Autowired
    private MetaFuncPermService metaFuncPermService;
    @Autowired
    private MetaDataPermCheckService metaDataPermCheckService;

    @Override
    public ConditionsWrapper buildWrapper(Query query, ConditionsWrapper wrapper) {
        if (query == null) {
            return ConditionsWrapper.builder();
        }

        List<Condition> strategy = query.getStrategy();
        FuncQueryStrategy strategyBean = query.getStrategyBean();
        String funcOrderSql = query.getFuncOrderSql();
        String funcWhereSql = query.getFuncWhereSql();
        List<Order> orders = query.getOrder();
        JSONObject formData = query.getFormData();
        String funcCode =query.getFuncCode();

        //是否覆盖功能where语句
        boolean isOverride = query.isOverrideFuncWhere();
        //是否覆盖功能Order语句
        boolean isOverrideFuncOrder = query.isOverrideFuncOrder();
        //查询策略
        if (strategyBean != null) {
            //是否覆盖
            if ("1".equals(strategyBean.getIsOverride())) {
                isOverride = true;
            }
            //自定义js脚本优先级高于sql
            if (strategy != null && !strategy.isEmpty()) {
                wrapper.and(i -> {
                    strategy.forEach(p -> {
                        condition(i, p);
                    });
                });
            } else if (StringUtils.isNotBlank(strategyBean.getSql())) {
                wrapper.and(i -> i.apply(formatVariable(i, trimSql(strategyBean.getSql()))));
            }
        } else if (strategy != null && !strategy.isEmpty()) {
            wrapper.and(i -> {
                strategy.forEach(p -> {
                    condition(i, p);
                });
            });
        }

        if(StringUtil.isNotEmpty(funcCode)){
            isOverride = funcPermBuild(isOverride,funcCode,wrapper);
        }
        //添加功能whereSql
        if (!isOverride && StringUtils.isNotBlank(funcWhereSql)) {
            wrapper.and(i -> i.apply(formatVariable(i, trimSql(funcWhereSql))));
        }

        if (formData != null && "select".equals(formData.getString("__type"))) {
            //查询选择
            String fieldId = formData.getString("__fieldId");
            //获取配置
            if (StringUtils.isNotBlank(fieldId)) {

                String fieldConfig = "";

                if (StringUtils.isNotBlank(query.getAppId())) {
                    //app查询选择
                    JSONObject appFunc = query.getAppFunc();
                    //获取字段配置
                    JSONArray fields = appFunc.getJSONArray("fields");
                    for (int i = 0; i < fields.size(); i++) {
                        JSONObject field = fields.getJSONObject(i).getJSONObject("values");
                        if (field.equals(field.getString("JE_PHONE_APPFIELD_ID"))) {
                            fieldConfig = field.getString("APPFIELD_WHERESQL");
                            break;
                        }
                    }
                } else {
                    //pc查询选择
                    String selectConfigSql = "select RESOURCEFIELD_WHERESQL from JE_CORE_RESOURCEFIELD where JE_CORE_RESOURCEFIELD_ID = {0}";
                    List<Map<String, Object>> list = metaResourceService.selectMap(selectConfigSql, fieldId);
                    if (list != null && !list.isEmpty() && list.get(0) != null) {
                        //查询选择配置的条件，有 Sq语句，condition数组 两种格式
                        fieldConfig = O2S.apply(list.get(0).get("RESOURCEFIELD_WHERESQL"));
                    }
                }

                //解析查询选择过滤条件配置
                if (StringUtils.isNotBlank(fieldConfig)) {
                    try {
                        //转换为条件数组
                        List<Condition> configs = JSON.parseArray(fieldConfig, Condition.class);
                        //变量
                        wrapper.and(configs != null && !configs.isEmpty(), i -> {
                            for (Condition p : configs) {
                                condition(i, p, formData);
                            }
                        });
                    } catch (JSONException e) {
                        //转换JSON失败视为 sql语句
                        String fieldConfigTemp = fieldConfig;
                        wrapper.and(i -> i.apply(formatVariable(i, trimSql(fieldConfigTemp), formData)));
                    }
                }
            }
        } else if (formData != null && "child".equals(formData.getString("__type"))) {
            //子功能
            String mainFuncId = formData.getString("__mainFuncId");
            String childFuncId = formData.getString("__childFuncId");
            if (StringUtils.isNotBlank(mainFuncId) && StringUtils.isNotBlank(childFuncId)) {
                String childConfigSql = "select * from JE_CORE_ASSOCIATIONFIELD where ASSOCIATIONFIELD_FID = {0} AND ASSOCIATIONFIELD_PID = {1}";
                List<Map<String, Object>> childConfigs = metaResourceService.selectMap(childConfigSql, mainFuncId, childFuncId);
                if (childConfigs != null && !childConfigs.isEmpty()) {
                    wrapper.and(i -> {
                        childConfigs.forEach(config -> {
                            //where条件 0或1
                            boolean whereCon = O2B.test(config.get("ASSOCIATIONFIELD_WHERECON"));
                            //传值 0或1
                            boolean transmit = O2B.test(config.get("ASSOCIATIONFIELD_TRANSMIT"));
                            //关联关系
                            String type = O2S.apply(config.get("ASSOCIATIONFIELD_ASSOCIATION"));
                            if (whereCon && StringUtils.isNotBlank(type)) {
                                //自定义sql
                                if ("IDIT".equalsIgnoreCase(type)) {
                                    String sql = O2S.apply(config.get("ASSOCIATIONFIELD_SQL"));
                                    //拼接自定义sql
                                    i.and(StringUtils.isNotBlank(sql), j -> j.apply(formatVariable(j, trimSql(sql), formData)));
                                } else if (transmit) {
                                    //子功能字段
                                    String code = O2S.apply(config.get("ASSOCIATIONFIELD_CHIFIELDCODE"));
                                    //主功能字段值
                                    Object value = formData.get(code);
                                    //拼接传值条件
                                    condition(i, new Condition(code, type, value));
                                }
                            }
                        });
                    });
                }
            }
        }

        //Condition转whereSql
        List<Condition> conditions = mixCondition(query);
        wrapper.and(conditions != null && !conditions.isEmpty(), i -> {
            conditions.forEach(p -> {
                condition(i, p);
            });
        });

        //mark处理
        List<Condition> mark = query.getMark();
        if (mark != null && !mark.isEmpty()) {
            //拼接条件
            ConditionsWrapper select = wrapper.child()
                    .eq("MARK_USERID", SecurityUserHolder.getCurrentAccountRealUserId())
                    .eq("MARK_FUNCID", query.getFuncId())
                    .and(i -> {
                        mark.forEach(p -> {
                            condition(i, p);
                        });
                    });
            //添加inSelect条件
            String inSelectSql = String.format("SELECT MARK_MODELID FROM JE_CORE_MARK WHERE %s", select.getSql());
            wrapper.inSql(query.getFuncPkCode(), inSelectSql);
        }

        //添加自定义sql，此sql前端无法赋值
        String applySql = query.getApplySql();
        wrapper.and(StringUtils.isNotBlank(applySql), i -> {
            i.apply(trimSql(applySql));
        });

        //前端order条件
        StringBuffer orderBuffer = new StringBuffer();
        //功能orderSql
        if (StringUtils.isNotBlank(funcOrderSql)&&!isOverrideFuncOrder) {
            orderBuffer.append(" ").append(trimSql(funcOrderSql)).append(",");
        }

        if (orders != null && !orders.isEmpty()) {
            String orderPattern = "\\s+(asc|desc)";
            Pattern pattern;
            Matcher matcher;
            boolean funcHasThisOrder;
            for (Order eachOrder : orders) {
                funcHasThisOrder = false;
                if (!Strings.isNullOrEmpty(funcOrderSql)) {
                    orderPattern = eachOrder.getCode().toLowerCase() + orderPattern;
                    pattern = Pattern.compile(orderPattern);
                    matcher = pattern.matcher(funcOrderSql.toLowerCase());
                    if (matcher.find()) {
                        funcHasThisOrder = true;
                    }
                }
                if (!funcHasThisOrder) {
                    orderBuffer.append(" ").append(trimBlank(eachOrder.getCode())).append(" ").append(trimBlank(eachOrder.getType())).append(",");
                }
            }
        }

        //拼接order
        if (orderBuffer.length() > 0) {
            //删除末尾逗号
            orderBuffer.deleteCharAt(orderBuffer.length() - 1);
            //加入wrapper
            wrapper.apply(Conditions.ORDER_BY.getSqlSegment());
            wrapper.apply(orderBuffer.toString());
        }

        return wrapper;
    }

    public boolean funcPermBuild(boolean isOverride, String funcCode, ConditionsWrapper wrapper) {
            //快速授权
            String quickQuerySql = metaDataPermCheckService.outputQuickQuerySql(funcCode);

            /**
             * 角色sql授权
             * 一个人可能有多个角色
             */
            //当前账号所属的角色集合
            RoleSqlAuthVo roleSqlAuthVo =  metaFuncPermService.getRoleSqlAuth(funcCode);
            //若授权开关开启
            String finalSql ="";
            if(roleSqlAuthVo!=null&&"1".equals(roleSqlAuthVo.getAuthOnOff())){
                String roleSql ="";
                String deptSql ="";
                String orgSql="";
                List<RoleSqlAuthScopeVo> deptRoleSqlList  =roleSqlAuthVo==null?null:roleSqlAuthVo.getRoleSqlAuthDeptList();
                if(deptRoleSqlList!=null&&deptRoleSqlList.size()>0){
                    String accountDepartmentId ="";
                    if(SecurityUserHolder.getCurrentAccountDepartment()==null){
                        accountDepartmentId =  SecurityUserHolder.getCurrentAccountRealOrgId();
                    }else {
                        accountDepartmentId = SecurityUserHolder.getCurrentAccountDepartment().getId();
                    }
                    for(RoleSqlAuthScopeVo roleSqlAuthScopeVo:deptRoleSqlList){
                        String deptId = roleSqlAuthScopeVo.getId();
                        String sql = roleSqlAuthScopeVo.getSql();
                        String isCover = roleSqlAuthScopeVo.getCoverSql();
                        String sqlStr ="";
                        if(accountDepartmentId!=null&&accountDepartmentId.equals(deptId)&&StringUtil.isNotEmpty(sql)){
                            sqlStr+=formatVariable(wrapper,trimSql(sql));
                            if("1".equals(isCover)){
                                isOverride=true;
                            }
                            if(StringUtil.isEmpty(deptSql)){
                                deptSql+="("+sqlStr+")";
                            }else{
                                deptSql+=" OR ("+sqlStr+")";
                            }
                        }
                    }
                }
                List<RoleSqlAuthScopeVo> orgRoleSqlList  =roleSqlAuthVo==null?null:roleSqlAuthVo.getRoleSqlAuthOrgList();
                if(orgRoleSqlList!=null&&orgRoleSqlList.size()>0){
                    String accountRealOrgId = SecurityUserHolder.getCurrentAccountRealOrgId();
                    for(RoleSqlAuthScopeVo roleSqlAuthScopeVo:orgRoleSqlList){
                        String orgId = roleSqlAuthScopeVo.getId();
                        String sql = roleSqlAuthScopeVo.getSql();
                        String isCover = roleSqlAuthScopeVo.getCoverSql();
                        String sqlStr ="";
                        if(accountRealOrgId!=null&&accountRealOrgId.equals(orgId)&&StringUtil.isNotEmpty(sql)){
                            sqlStr+=formatVariable(wrapper,trimSql(sql));
                            if("1".equals(isCover)){
                                isOverride=true;
                            }
                            if(StringUtil.isEmpty(orgSql)){
                                orgSql+="("+sqlStr+")";
                            }else{
                                orgSql+=" OR ("+sqlStr+")";
                            }
                        }
                    }
                }
                List<RoleSqlAuthScopeVo> roleRoleSqlList  =roleSqlAuthVo==null?null:roleSqlAuthVo.getRoleSqlAuthRoleList();
                if(roleRoleSqlList!=null&&roleRoleSqlList.size()>0){
                    List<String> roleIds = SecurityUserHolder.getCurrentAccount().getRoleIds();
                    for(RoleSqlAuthScopeVo roleSqlAuthScopeVo:roleRoleSqlList){
                        String roleid = roleSqlAuthScopeVo.getId();
                        String sql = roleSqlAuthScopeVo.getSql();
                        String isCover = roleSqlAuthScopeVo.getCoverSql();
                        String sqlStr ="";
                        if(roleIds!=null&&roleIds.contains(roleid)&&StringUtil.isNotEmpty(sql)){
                            sqlStr+=formatVariable(wrapper,trimSql(sql));
                            if("1".equals(isCover)){
                                isOverride=true;
                            }
                            if(StringUtil.isEmpty(roleSql)){
                                roleSql+="("+sqlStr+")";
                            }else{
                                roleSql+=" OR ("+sqlStr+")";
                            }
                        }
                    }
                }
                if(StringUtil.isNotEmpty(roleSql)){
                    finalSql+="("+roleSql+")";
                }
                if(StringUtil.isNotEmpty(orgSql)){
                    if(StringUtil.isEmpty(finalSql)){
                        finalSql+="("+orgSql+")";
                    }else {
                        finalSql+=" OR ("+orgSql+")";
                    }
                }
                if(StringUtil.isNotEmpty(deptSql)){
                    if(StringUtil.isEmpty(finalSql)){
                        finalSql+="("+deptSql+")";
                    }else {
                        finalSql+=" OR ("+deptSql+")";
                    }
                }
            }
        String finalSql1 = finalSql;
        wrapper.and(i -> {
            //快速授权
            if(StringUtil.isNotEmpty(quickQuerySql)){
                i.apply(formatVariable(i,trimSql(quickQuerySql)));
            }
            //角色授权
            if(StringUtil.isNotEmpty(finalSql1)){
                if(StringUtil.isEmpty(i.getSql())){
                    i.apply(finalSql1);
                }else {
                    i.apply(" OR ");
                    i.apply(finalSql1);
                }
            }

            //sql授权
            String sql = metaFuncPermService.getSqlAuth(funcCode);
            if(StringUtil.isEmpty(i.getSql())){
                if(StringUtil.isNotEmpty(sql)){
                    i.apply(formatVariable(i,trimSql(sql)));
                }
            }else {
                if(StringUtil.isNotEmpty(sql)){
                    i.apply(" OR ");
                    i.apply(formatVariable(i,trimSql(sql)));
                }
            }

        });
        return isOverride;
    }
}
